/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package com.butnet.myframe.template.impl;

import java.io.PrintWriter;
import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.butnet.myframe.template.Template;
import com.butnet.myframe.template.TemplateNode;
import com.butnet.myframe.template.TemplateNodeList;

/**
 * 
 * @author Administrator
 */
public class TemplateNodeImpl implements TemplateNode {
	public final static int TEMPLATE = -1;
	public final static int ROOT = 0;
	public final static int TEXT = 1;
	public final static int EXPRESSION = 2;

	private Template template = null;
	private int level = -1;
	private TemplateNode parentNode = null;
	private TemplateNodeListImpl childs = new TemplateNodeListImpl();
	private Map<String, Object> dataContent = null;
	private String nodeName = null;
	private String textContent = null;
	private Map<String, Object> attributes = new LinkedHashMap<String, Object>();

	protected TemplateNodeImpl() {
	}

	public TemplateNodeImpl(int level) {
		this.level = level;
	}

	public TemplateNodeImpl(int level, String nodeName) {
		this.level = level;
		this.nodeName = nodeName;
	}

	@Override
	public Map<String, Object> getDataContent() {
		if (isRecursion)
			return dataContent;
		isRecursion = true;
		if (dataContent == null) {
			dataContent = getParentNode() == null ? getOwnerTemplate().getDataContent() : getParentNode()
					.getDataContent();
			isRecursion = false;
		} else
			isRecursion = false;
		return dataContent;
	}

	@Override
	public void setDataContent(Map<String, Object> dataContent) {
		this.dataContent = dataContent;
	}

	@Override
	public void putData(String name, Object value) {
		if (this.dataContent == null)
			this.dataContent = new LinkedHashMap<String, Object>();
		this.dataContent.put(name, value);
	}

	@Override
	public Object removeData(String name) {
		return this.dataContent.remove(name);
	}

	@Override
	public boolean containData(String name) {
		return this.dataContent.containsKey(name);
	}

	@Override
	public TemplateNode appendChild(TemplateNode newNode) {
		if (childs.contains(newNode)) {
			childs.remove(newNode);
		}
		childs.add(newNode);
		newNode.setParentNode(this);
		return newNode;
	}

	@Override
	public TemplateNodeList getChildNodes() {
		return childs;
	}

	@Override
	public TemplateNode getFirstChild() {
		if (childs.getLength() == 0)
			return null;
		return childs.get(0);
	}

	@Override
	public TemplateNode getLastChild() {
		if (childs.getLength() == 0)
			return null;
		return childs.get(childs.getLength() - 1);
	}

	@Override
	public TemplateNode getNextSibling() {
		TemplateNode p = getParentNode();
		if (p == null)
			return null;
		return p.getChildNodes().item(p.indexOf(this) + 1);
	}

	@Override
	public String getNodeName() {
		if (nodeName != null)
			return nodeName;
		switch (level) {
		case ROOT:
			return "Root";
		case TEXT:
			return "Text";
		case EXPRESSION:
			return "Expression";
		default:
			return "Undefine";
		}
	}

	@Override
	public Template getOwnerTemplate() {
		return template;
	}

	@Override
	public void setOwnerTemplate(Template template) {
		this.template = template;
		if (isRecursion) {
			isRecursion = false;
			System.out.println("警告： 此树有回环");
			return;
		}
		isRecursion = true;
		for (TemplateNode n : childs)
			n.setOwnerTemplate(template);
		isRecursion = false;
	}

	@Override
	public TemplateNode getParentNode() {
		return parentNode;
	}

	@Override
	public void setParentNode(TemplateNode parentNode) {
		this.parentNode = parentNode;
	}

	@Override
	public String getTextContent() {
		return textContent;
	}

	@Override
	public void setTextContent(String textContent) {
		this.textContent = textContent;
	}

	@Override
	public TemplateNode insertBefore(TemplateNode newChild, TemplateNode refChild) {
		if (childs.contains(newChild))
			childs.remove(newChild);
		int index = childs.indexOf(refChild);
		if (index == -1) {
			childs.add(newChild);
		} else
			childs.add(index, newChild);
		newChild.setParentNode(this);
		return newChild;
	}

	@Override
	public TemplateNode removeChild(TemplateNode oldChild) {
		if (childs.contains(oldChild)) {
			childs.remove(oldChild);
			return oldChild;
		}
		return null;
	}

	@Override
	public TemplateNode replaceChild(TemplateNode newChild, TemplateNode oldChild) {
		int index = childs.indexOf(oldChild);
		if (index == -1) {
			return null;
		} else {
			childs.set(index, newChild);
			newChild.setParentNode(this);
			return newChild;
		}
	}

	@Override
	public int indexOf(TemplateNode childNode) {
		return childs.indexOf(childNode);
	}

	@Override
	public void setAttribute(String name, Object value) {
		attributes.put(name, value);
	}

	@Override
	public Object getAttribute(String name) {
		return attributes.get(name);
	}

	@Override
	public Object removeAttribute(String name) {
		return attributes.remove(name);
	}

	@Override
	public void translate(PrintWriter out) {
		if (level == TEXT) {
			translateText(out);
		} else if (level == TEMPLATE) {
			getOwnerTemplate().root().translate(out);
		} else if (level == EXPRESSION) {
			// 翻译自己
			String nodeName = getNodeName();
			if ("if".equalsIgnoreCase(nodeName)) {
				String tc = getTextContent();
				tc = tc.trim();
				if (!tc.startsWith("!")) {
					if (translateData(tc) != null) {
						this.setAttribute("success", true);
						// 翻译子结点
						for (int i = 0; i < childs.size(); i++)
							childs.get(i).translate(out);
					} else {
						this.setAttribute("success", false);
						for (int i = 0; i < childs.size(); i++) {
							TemplateNode tn = childs.get(i);
							if ("else".equalsIgnoreCase(tn.getNodeName())) {
								tn.translate(out);
							} else if ("elseif".equalsIgnoreCase(tn.getNodeName())) {
								tn.translate(out);
							}
						}
					}
				} else {
					if (translateData(tc.substring(1)) == null) {
						this.setAttribute("success", true);
						// 翻译子结点
						for (int i = 0; i < childs.size(); i++)
							childs.get(i).translate(out);
					} else {
						this.setAttribute("success", false);
						for (int i = 0; i < childs.size(); i++) {
							TemplateNode tn = childs.get(i);
							if ("else".equalsIgnoreCase(tn.getNodeName())) {
								tn.translate(out);
							} else if ("elseif".equalsIgnoreCase(tn.getNodeName())) {
								tn.translate(out);
							}
						}
					}
				}

			} else if ("else".equalsIgnoreCase(nodeName)) {
				TemplateNode pNode = getParentNode();
				while (pNode != null) {
					if ("if".equalsIgnoreCase(pNode.getNodeName()) && !(Boolean) pNode.getAttribute("success")) {
						for (int i = 0; i < childs.size(); i++) {
							childs.get(i).translate(out);
						}
						break;
					} else {
						pNode = pNode.getParentNode();
					}
				}
			} else if ("elseif".equalsIgnoreCase(nodeName)) {
				TemplateNode pNode = getParentNode();
				while (pNode != null) {
					if ("if".equalsIgnoreCase(pNode.getNodeName()) && !(Boolean) pNode.getAttribute("success")) {
						for (int i = 0; i < childs.size(); i++)
							childs.get(i).translate(out);
						break;
					} else {
						pNode = pNode.getParentNode();
					}
				}
			} else if ("for".equalsIgnoreCase(nodeName)) {
				String tc = getTextContent();
				String tcs[] = tc.split("\\s+[Ii][Nn]\\s+");
				Object for_obj = translateData(tcs[1].trim());
				if (for_obj != null) {
					Object oldData = dataContent.get("");

					Map<String, Object> tempMap = new LinkedHashMap<String, Object>();
					dataContent.put("", tempMap);

					if (oldData != null)
						tempMap.put("", oldData);

					int index = 0;
					Object item = null;
					item = getDataByBeanName(for_obj, String.valueOf(index));
					String indexName = tcs[0].trim();

					while (item != null) {
						tempMap.put(indexName, item);
						tempMap.put("index", index);

						// 翻译子结点
						for (int i = 0; i < childs.size(); i++)
							childs.get(i).translate(out);

						index++;
						item = getDataByBeanName(for_obj, String.valueOf(index));
					}

					dataContent.remove("");
					if (oldData != null)
						dataContent.put("", oldData);
				}
			}
		} else if (level == ROOT) {
			// 只翻译子结点
			for (int i = 0; i < childs.size(); i++)
				childs.get(i).translate(out);
		}
	}

	/**
	 * 翻译文本
	 * 
	 * @param out
	 */
	private void translateText(PrintWriter out) {
		String regex = "\\$\\s*\\{[^\\}]+\\}";// 解析文本中的变量表达式
		Pattern pattern = Pattern.compile(regex);
		Matcher matcher = pattern.matcher(textContent);
		int start = 0;
		String varStr = null;
		StringBuilder buff = new StringBuilder();
		while (matcher.find(start)) {
			buff.append(textContent.subSequence(start, matcher.start()));
			start = matcher.start();
			if (start > 0) {
				varStr = matcher.group();
				if (textContent.charAt(start - 1) != '\\') {
					buff.append(translateData(varStr.substring(varStr.indexOf('{') + 1, varStr.length() - 1)));// 翻译数据
				} else {
					if(buff.charAt(buff.length()-1)=='\\')
						buff.delete(buff.length()-1, buff.length());
					buff.append(varStr);// 直译文本
				}
				start += varStr.length();
			} else {
				varStr = matcher.group();
				buff.append(translateData(varStr.substring(varStr.indexOf('{') + 1, varStr.length() - 1)));// 翻译数据
				start += varStr.length();
			}
		}
		buff.append(textContent.substring(start));

		out.print(buff.toString());
	}

	/**
	 * 翻译数据
	 * 
	 * @param p
	 *            数据对象访问路径(如: users[0].name)
	 * @return
	 */
	private Object translateData(String p) {
		if (p.length() == 0)
			return null;
		// 取得路径代表的数据对象
		Object o = getDataByBeanName(p);
		return o == null ? null : o;
	}

	/**
	 * 取得访问的对象
	 * 
	 * @param n
	 * @return
	 */
	private Object getDataByBeanName(String n) {
		String oldName = n;
		int index = -1;
		Object obj = null;
		do {
			if ((index = n.indexOf('[')) != -1) {
				n = n.substring(0, index).trim();
				oldName = oldName.substring(index + 1).trim();
			} else
				oldName = null;
			String[] ns = n.split("\\.");// 按对象运算符分割
			obj = getDataContent();
			for (String i : ns) {
				i = i.trim();
				String[] array = parseArray(i);// 检查是否有数组下标
				obj = getDataByBeanName(obj, array[0].trim());// 取bean数据对象
				for (int j = 1; j < array.length; j++) {
					if (obj instanceof Object[]) {
						obj = Array.get(obj, Integer.parseInt(array[j]));
					} else {
						obj = getDataByBeanName(obj, array[j].trim());
					}
				}
			}
			if (index != -1 && obj != null) {
				index = oldName.indexOf(']');
				if (index == -1)
					return null;
				String indexName = oldName.substring(0, index);
				if (isNumber(indexName))
					obj = getDataByBeanName(obj, indexName);
				else {
					Object v = getDataByBeanName(indexName);
					indexName = v == null ? null : v.toString();
					if (indexName == null)
						return null;
					obj = getDataByBeanName(obj, indexName);
				}
				oldName = oldName.substring(index + 1).trim();
			}
		} while ((oldName != null && oldName.length() > 0) && obj != null);
		return obj;
	}

	private boolean isNumber(String str) {
		try {
			Integer.parseInt(str);
			return true;
		} catch (Exception e) {
			return false;
		}
	}

	/**
	 * 解析对象名称中的数据下标
	 * 
	 * @param n
	 * @return
	 */
	private String[] parseArray(String n) {
		if (array_pattern == null)
			array_pattern = Pattern.compile("\\[[^\\]]+\\]");
		Matcher m = array_pattern.matcher(n);
		if (m.find()) {
			List<String> l = new LinkedList<String>();
			l.add(n.substring(0, m.start()));
			String indexName = m.group();
			int start = m.start() + indexName.length();
			indexName = indexName.substring(1, indexName.length() - 1).trim();
			System.out.println(".............. " + indexName);
			l.add(indexName);
			while (m.find(start)) {
				indexName = m.group();
				start = m.start() + indexName.length();
				indexName = indexName.substring(1, indexName.length() - 1).trim();
				l.add(indexName);
			}
			return l.toArray(new String[0]);
		} else {
			return new String[] { n };
		}
	}

	/**
	 * 取对象属性数据
	 */
	private Object getDataByBeanName(Object obj, String beanName) {
		if (obj instanceof Map<?, ?>) {
			Map<?, ?> m = (Map<?, ?>) obj;
			return m.get(beanName);
		} else if (obj instanceof Object[]) {
			int index = -1;
			try {
				index = Integer.parseInt(beanName);
			} catch (Exception e) {
			}
			if (index != -1) {
				if (index < Array.getLength(obj))
					return Array.get(obj, index);
				return null;
			} else {
				return getDataByBeanPropertyName(obj, beanName);
			}
		} else if (obj instanceof List<?>) {
			int index = -1;
			try {
				index = Integer.parseInt(beanName);
			} catch (Exception e) {
			}
			if (index != -1) {
				if (index < ((List<?>) obj).size())
					return ((List<?>) obj).get(index);
				return null;
			} else
				return getDataByBeanPropertyName(obj, beanName);
		} else if (obj instanceof Set<?>) {
			Set<?> s = (Set<?>) obj;
			int index = -1;
			try {
				index = Integer.parseInt(beanName);
			} catch (Exception e) {
			}
			if (index != -1) {
				if (index < s.size())
					return s.toArray()[index];
				return null;
			} else {
				return getDataByBeanPropertyName(obj, beanName);
			}
		} else if (obj instanceof Object) {
			return getDataByBeanPropertyName(obj, beanName);
		}
		return null;
	}

	/**
	 * 通过对象的getXXX方法取得属性值
	 * 
	 * @param obj
	 *            bean对象
	 * @param propertyName
	 *            属性名称如:name －－＞ 调用getName方法
	 * @return
	 */
	private Object getDataByBeanPropertyName(Object obj, String propertyName) {
		String methodName = "get" + (propertyName.charAt(0) + "").toUpperCase() + propertyName.substring(1);
		try {
			Method m = obj.getClass().getMethod(methodName, (Class<?>[]) null);
			if (m == null)
				return null;
			m.setAccessible(true);
			return m.invoke(obj, (Object[]) null);
		} catch (SecurityException e) {
		} catch (NoSuchMethodException e) {
		} catch (IllegalArgumentException e) {
		} catch (IllegalAccessException e) {
		} catch (InvocationTargetException e) {
		}
		return null;
	}

	/**
	 * 判断setOwnerTemplate是否因子结点遍历而递归
	 */
	private boolean isRecursion = false;
	/**
	 * 解析数组下标的正则表达式
	 */
	private Pattern array_pattern = null;
}
